/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.huize.ladon.apm.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Type;
import java.util.TimeZone;

/**
 * 描述:  Json工具类,从{@code com.hzins.bsp.common.util.HzJsonUtils.java}移植过来,减少apm项目依赖
 *
 * @author tianyuliang
 * @version $Id: HzJsonUtils.java, v0.1 2019/4/12
 */
@SuppressWarnings("unchecked")
public class HzJsonUtils {

    public static final String LANG_OF_JAVA = "JAVA";

    private static final Boolean DEFAULT_CREATE_NEW_MAPPER = false;

    private static final String LANG_OF_C_SHARP_AUTO_CONVERT = "C_SHARP_AUTO_CONVERT";

    private static final HzObjectMapperUtils JAVA_OBJECT_MAPPER = buildDefaultObjectMapper();

    private static final HzObjectMapperUtils C_SHARP_OBJECT_MAPPER;

    static {
        C_SHARP_OBJECT_MAPPER = buildDefaultObjectMapper();
        C_SHARP_OBJECT_MAPPER.setPropertyNamingStrategy(new PropertyNamingStrategy.PropertyNamingStrategyBase() {
            private static final long serialVersionUID = 1L;

            @Override
            public String translate(String propertyName) {
                String result = null;
                char firstWorld = propertyName.charAt(0);
                String first = String.valueOf(firstWorld);
                if (Character.isUpperCase(firstWorld)) {
                    result = first.toLowerCase() + propertyName.substring(1);
                } else {
                    result = first.toUpperCase() + propertyName.substring(1);
                }
                return result;
            }
        });
    }

    /**
     * 忽略空字段 获取ObjectMapper实例
     *
     * @param isCreateNewMapper 方式：true，新实例；false,存在的mapper实例
     * @return
     */
    public static HzObjectMapperUtils getMapperInstance(boolean isCreateNewMapper) {
        HzObjectMapperUtils objectMapper;
        if (isCreateNewMapper) {
            objectMapper = buildDefaultObjectMapper();
        } else {
            objectMapper = JAVA_OBJECT_MAPPER;
        }
        return objectMapper;
    }


    /**
     * 忽略空字段 获取ObjectMapper实例
     *
     * @param isCreateNewMapper 方式 true:新实例；false:存在的mapper实例
     * @param isPrettyPrint     是否Pretty格式化，true:美化输出; false:默认输出，不格式化
     * @return
     */
    public static HzObjectMapperUtils getMapperInstance(boolean isCreateNewMapper, boolean isPrettyPrint) {
        if (isPrettyPrint) {
            return buildDefaultPrettyPrintObjectMapper();
        }
        return getMapperInstance(isCreateNewMapper);
    }

    /**
     * 构建默认实例
     *
     * @return
     */
    private static HzObjectMapperUtils buildDefaultObjectMapper() {
        HzObjectMapperUtils objectMapper = new HzObjectMapperUtils();

        objectMapper.getFactory().enable(JsonFactory.Feature.INTERN_FIELD_NAMES);
        objectMapper.getFactory().enable(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES);
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);

        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);// fix: Could not write content: No serializer found for Collections and no properties discovered to create BeanSerializer
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.setDateFormat(new HzStdDateFormatUtils());
        objectMapper.registerModule(new JodaModule());
        return objectMapper;
    }

    /**
     * 构建“启用PrettyPrint”美化输出json的实例
     *
     * @return
     */
    private static HzObjectMapperUtils buildDefaultPrettyPrintObjectMapper() {
        HzObjectMapperUtils objectMapper = buildDefaultObjectMapper();
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT); // 启用json“美化”输出效果
        return objectMapper;
    }

    /**
     * 将java对象转换成json字符串
     *
     * @param obj 准备转换的对象
     * @return
     * @throws Exception
     */
    public static String beanToJson(Object obj) {
        if (obj == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER);
            String json = objectMapper.writeValueAsString(obj);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将java对象转换成json字符串,同时对json美化输出
     *
     * @param obj 准备转换的对象
     * @return
     * @throws Exception
     */
    public static String beanToPrettyJson(Object obj) {
        if (obj == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER, true);
            String json = objectMapper.writeValueAsString(obj);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将java对象转换成json字符串，忽略@Annotaion
     *
     * @param obj 准备转换的对象
     * @return
     * @throws Exception
     */
    public static String beanToJsonIgnoreAnnotaion(Object obj) {
        if (obj == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(true);
            objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
            String json = objectMapper.writeValueAsString(obj);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将java对象转换成json字符串
     *
     * @param obj       准备转换的对象
     * @param createNew ObjectMapper实例方式:true，新实例;false,存在的mapper实例
     * @return
     * @throws Exception
     */
    public static String beanToJson(Object obj, Boolean createNew) {
        if (obj == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(createNew);
            String json = objectMapper.writeValueAsString(obj);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字符串转换成java对象
     *
     * @param json  准备转换的json字符串
     * @param clazz 准备转换的类
     * @return
     * @throws Exception
     */
    public static <T> T jsonToBean(String json, Class<T> clazz) {
        if (json == null) {
            return null;
        }

        T t = null;
        try {
            if (String.class.equals(clazz)) {
                t = (T) json;
                return t;
            }

            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER);
            t = objectMapper.readValue(json, clazz);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字符串转换成java对象
     *
     * @param json 准备转换的json字符串
     * @param type 准备转换类的Type类型
     * @return
     * @throws Exception
     */
    public static <T> T jsonToBean(String json, Type type) {
        if (json == null) {
            return null;
        }

        T t = null;
        try {
            if (String.class.equals(type)) {
                t = (T) json;
                return t;
            }

            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER);
            t = objectMapper.readValue(json, type);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 将json字符串转换成java对象
     *
     * @param json     准备转换的json字符串
     * @param type     准备转换类的Type类型
     * @param language 转换语言
     * @return
     * @throws Exception
     */
    public static <T> T jsonToBean(String json, Type type, String language) {
        if (json == null) {
            return null;
        }

        T t = null;
        try {
            if (String.class.equals(type)) {
                t = (T) json;
                return t;
            }

            if (StringUtils.isNotBlank(json)) {
                HzObjectMapperUtils objectMapper = JAVA_OBJECT_MAPPER;
                if (LANG_OF_C_SHARP_AUTO_CONVERT.equals(language)) {
                    objectMapper = C_SHARP_OBJECT_MAPPER;
                }
                t = objectMapper.readValue(json, type);
                return t;
            }

            t = (T) json;
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 将json字符串转换成java对象
     *
     * @param json          准备转换的json字符串
     * @param typeReference 准备转换类的TypeReference类型
     * @return
     * @throws Exception
     */
    public static <T> T jsonToBean(String json, TypeReference<T> typeReference) {
        if (json == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER);
            T t = objectMapper.readValue(json, typeReference);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字符串转换成java对象
     *
     * @param json      准备转换的json字符串
     * @param clazz     准备转换的类
     * @param createNew ObjectMapper实例方式 true:新实例, false:存在的mapper实例
     * @return
     * @throws Exception
     */
    public static <T> T jsonToBean(String json, Class<T> clazz, Boolean createNew) {
        if (json == null) {
            return null;
        }

        T t = null;
        try {
            if (String.class.equals(clazz)) {
                t = (T) json;
                return t;
            }

            HzObjectMapperUtils objectMapper = getMapperInstance(createNew);
            t = objectMapper.readValue(json, clazz);
            return t;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将Object对象转换为json字符串
     *
     * @param object   Object对象
     * @param language 转换语言
     * @return
     */
    public static String beanToJson(Object object, String language) {
        if (object == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = JAVA_OBJECT_MAPPER;
            if (LANG_OF_C_SHARP_AUTO_CONVERT.equals(language)) {
                objectMapper = C_SHARP_OBJECT_MAPPER;
            }
            String json = objectMapper.writeValueAsString(object);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将可变对象转换为json字符串
     *
     * @param objects
     * @return
     */
    public static String beanToJson(Object... objects) {
        if (objects == null) {
            return null;
        }

        try {
            HzObjectMapperUtils objectMapper = getMapperInstance(DEFAULT_CREATE_NEW_MAPPER);
            String json = objectMapper.writeValueAsString(objects);
            return json;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判断是否为json格式字符串
     *
     * @param value
     * @return
     */
    public static boolean isJson(String value) {
        boolean isJson = false;
        if (StringUtils.isNotBlank(value)) {
            isJson = (value.startsWith("{") && value.endsWith("}")) || (value.startsWith("\"") && value.endsWith("\""));
        }
        return isJson;
    }

}
